package cn.tedu.csmall.passport.service.impl;

import cn.tedu.csmall.passport.ex.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.pojo.dto.AdminAddNewDTO;
import cn.tedu.csmall.passport.pojo.dto.AdminLoginDTO;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.IAdminService;
import cn.tedu.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminRoleMapper adminRoleMapper;
    @Autowired
    AuthenticationManager authenticationManager;

    @Value("${csmall.jwt.secret-key}")
    private String secretKey;
    @Value("${csmall.jwt.duration-in-minute}")
    private Long durationInMinute;

    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        log.debug("开始处理管理员登录的业务,参数:{}",adminLoginDTO);
        Authentication authentication
                = new UsernamePasswordAuthenticationToken(adminLoginDTO.getUsername(), adminLoginDTO.getPassword());
        log.debug("在这里调用");
        Authentication authenticateResult
                = authenticationManager.authenticate(authentication);
        log.debug("认证通过，认证管理器返回：{}", authenticateResult);

        //从认证结果中获取所需的数据, 将用于生成JWT
        Object principal = authenticateResult.getPrincipal();
        log.debug("认证结果中的当事人类型：{}", principal.getClass().getName());
        AdminDetails adminDetails = (AdminDetails) principal;
        Long id = adminDetails.getId();
        String username = adminDetails.getUsername();
        Collection<GrantedAuthority> authorities = adminDetails.getAuthorities();
        String authoritiesJsonString = JSON.toJSONString(authorities);
        //生成JWT数据时, 需要填充装到JWT中的数据
        Map<String, Object> claims = new HashMap<>();
        // claims.put("id", 9527);
        claims.put("id", id);
        claims.put("username", username);
        claims.put("authoritiesJsonString", authoritiesJsonString);
        log.debug("向JWT中存入id：{}", id);
        log.debug("向JWT中存入username：{}", username);
        log.debug("向JWT中存入authoritiesJsonString：{}", authoritiesJsonString);
        //以下是生成JWT的固定代码
        Date date = new Date(System.currentTimeMillis() +durationInMinute * 60 * 1000L);
        String jwt = Jwts.builder()
                        //Header
                        .setHeaderParam("alg","HS256")
                        .setHeaderParam("typ","JWT")
                        //payload
                        .setClaims(claims)
                        //Signature
                        .setExpiration(date)
                        .signWith(SignatureAlgorithm.HS256, secretKey)
                        .compact();
        log.debug("生成的JWT:{}",jwt);
        return jwt;
    }

    @Override
    public void AddNew(AdminAddNewDTO adminAddNewDTO) {
        log.debug("开始处理添加管理员的业务,参数:{}",adminAddNewDTO);
        //获取用户名
        String username = adminAddNewDTO.getUsername();
        //检查用户名是否存在
        int i = adminMapper.countByUsername(username);
        if (i>0) {
            //是: 添加失败,用户名已存在
            String message = "添加失败,用户名已存在";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        //否, 继续验证手机号码是否存在
        String phone = adminAddNewDTO.getPhone();
        log.debug("继续验证手机号码是否存在");
        i = adminMapper.countByPhone(phone);
        if (i>0) {
            //是: 添加失败,手机号已存在
            String message = "添加失败,手机号已存在";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        //否, 继续验证电子邮箱是否存在
        String email = adminAddNewDTO.getEmail();
        log.debug("继续验证电子邮箱是否存在");
        i = adminMapper.countByEmail(email);
        if (i>0) {
            //是: 添加失败,邮箱已存在
            String message = "添加失败,邮箱已存在";
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        //创建管理员对象
        log.debug("创建管理员对象");
        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewDTO, admin);
        admin.setLoginCount(0);
        //开始添加管理员
        log.debug("开始添加管理员, 参数:{}",admin);
        int insert = adminMapper.insert(admin);
        if (insert!=1) {
            String message = "添加失败,服务器忙,请稍后再试";
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        //插入管理员与角色关联的数据
        Long[] roleIds = adminAddNewDTO.getRoleIds();
        AdminRole[] adminRoles = new AdminRole[roleIds.length];
        for (i = 0; i< adminRoles.length; i++){
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRole.setGmtCreate(LocalDateTime.now());
            adminRole.setGmtModified(LocalDateTime.now());
            adminRoles[i] = adminRole;
        }
        i = adminRoleMapper.insertBatch(adminRoles);
        if (i != roleIds.length){
            String message = "批量添加失败, 服务器忙, 请稍后再试";
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理查询管理员列表的业务,无参数");
        List<AdminListItemVO> list = adminMapper.list();
        //不显示id为1的管理员
        Iterator<AdminListItemVO> iterator = list.iterator();
        while (iterator.hasNext()){
            AdminListItemVO item = iterator.next();
            if (item.getId()==1){
                iterator.remove();
                break;
            }
        }
        return list;
    }

    @Override
    public void delete(Long id) {
        log.debug("开始处理删除管理员列表的业务, 参数:{}",id);
        //id为1的管理员不能被删除
        if (id==1) {
            String message = "数据不存在,无法删除";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        //根据id查询是否存在该数据
        AdminStandardVO vo = adminMapper.getStandardById(id);
        if (vo == null) {
            //否: 数据不存在,无法删除,抛出异常
            String message = "数据不存在,无法删除";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        //是: 数据存在, 可以删除
        int i = adminMapper.deleteById(id);
        if (i != 1) {
            String message = "删除失败, 服务器忙, 请稍后再试";
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        //删除管理员与角色的关联数据
        int rows = adminRoleMapper.deleteByAdminId(id);
        if (rows<1) {
            String message = "删除失败, 服务器忙, 请稍后再试";
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
        log.debug("删除成功");
    }

    @Override
    public void setEnable(Long id) {
        updateById(id,1);
    }

    @Override
    public void unEnable(Long id) {
        updateById(id,0);
    }

    private void updateById(Long id, Integer enable){
        String[] s = {"取消启用","启用"};
        //判断id是否为1
        if (id==1) {
            String message = "管理员数据不存在,无法"+s[enable];
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        //根据id查询管理员对象是否不存在
        AdminStandardVO vo = adminMapper.getStandardById(id);
        //是: 抛出异常, 无法修改
        if (vo==null) {
            String message = "管理员数据不存在,无法"+s[enable];
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        //判断管理员启用状态是否已经是要修改的状态
        if (vo.getEnable()==enable) {
            String message = "当前管理员状态已经"+s[enable]+",无法修改";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        int i = adminMapper.update(admin);
        if (i != 1) {
            String message = "服务器忙,无法"+s[enable]+",请稍后再试";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        log.debug(s[enable]+"完成");
    }
}
